package enron;

//import java.text.DecimalFormat;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Vector;

import jade.core.Agent;
import jade.lang.acl.ACLMessage;
import jade.proto.ContractNetInitiator;

public class PurchaseEnergyBehaviour extends ContractNetInitiator {
	private static final long serialVersionUID = 5187664385927553141L;
	private int vendorCount = 0;
	
	public PurchaseEnergyBehaviour(Agent a, ACLMessage cfp, int vendorCount) {
		super(a, cfp);
		this.vendorCount = vendorCount;
	}

	@SuppressWarnings("rawtypes")
	protected void handlePropose(ACLMessage propose, Vector v) {
//		System.out.println("Auction: (" + myAgent.getAID().getLocalName()+") "+propose.getSender().getLocalName()+" proposed $"+propose.getContent()+"/kWh.");
	}

	protected void handleRefuse(ACLMessage refuse) {
//		System.out.println("Auction: (" + myAgent.getAID().getLocalName()+") "+refuse.getSender().getName()+" refused.");
	}

	protected void handleFailure(ACLMessage failure) {
		if (failure.getSender().equals(myAgent.getAMS())) {
			// FAILURE notification from the JADE runtime: the receiver
			// does not exist
//			System.out.println("Auction: " + "Responder does not exist");
		}
		else {
//			System.out.println("Auction: (" + myAgent.getAID().getLocalName()+") Agent "+failure.getSender().getName()+" failed");
		}
		vendorCount--;
		if(vendorCount == 0) {
			((BuyerAgent)myAgent).isPurchasing = false;
		}
	}

	@Override
	protected void handleAllResponses(@SuppressWarnings("rawtypes") Vector rawResponses, @SuppressWarnings("rawtypes") Vector rawAcceptances) {
		@SuppressWarnings("unchecked")
		Vector<ACLMessage> acceptances = rawAcceptances;
		@SuppressWarnings("unchecked")
		Vector<ACLMessage> responses = rawResponses;
		
		Vector<ACLMessage> replies = new Vector<ACLMessage>();
		
		//TODO Handle Iterations

		Integer iteration;
		double askingPrice = 0.0;

		Vector<ACLMessage> refused = new Vector<ACLMessage>();
		for(ACLMessage msg : responses) {
			if(msg.getPerformative() == ACLMessage.REFUSE) {
				refused.add(msg);
			}
		}
		
		responses.removeAll(refused);
		if(responses.size() >0){
			Collections.sort(responses, new Comparator<ACLMessage>(){

				@Override
				public int compare(ACLMessage msg1, ACLMessage msg2) {
					int returnVal = 0;
					if(msg1.getContent() == null) {
						returnVal = 1;
					} else if(msg2.getContent() == null) {
						returnVal = -1;
					} else {
						returnVal = Double.compare(Double.parseDouble(msg2.getContent()), Double.parseDouble(msg1.getContent()));
					}

					return returnVal;
				}

			});

			Double middle = Math.floor(responses.size()/2.0);
			List<ACLMessage> rejectList = responses.subList(0, middle.intValue());
			List<ACLMessage> acceptList = responses.subList(middle.intValue(), responses.size());
			
			vendorCount -= rejectList.size();

			double lowestProposal = 0.0;
			if(responses.lastElement().getContent() != null) {
				lowestProposal = Double.parseDouble(responses.get(responses.size()-1).getContent());
			}
			askingPrice = lowestProposal * 0.80;

			ACLMessage reply;
			for(ACLMessage msg : rejectList) {
				if (msg.getPerformative() == ACLMessage.PROPOSE) {
					iteration = Integer.parseInt(msg.getUserDefinedParameter("negotiationIteration"));
					iteration++;
					reply = msg.createReply();
					reply.setPerformative(ACLMessage.REJECT_PROPOSAL);
					reply.addUserDefinedParameter("negotiationIteration", iteration.toString());
					replies.addElement(reply);
//					System.out.println("Auction: " + myAgent.getLocalName() + " - " + msg.getSender().getLocalName() + " Price is too high, rejecting $" + msg.getContent() + "/kWh. (Iteration: "+ iteration +")");
				}
			}

			if(acceptList.size() > 1) {
				for(ACLMessage msg : acceptList) {
					if (msg.getPerformative() == ACLMessage.PROPOSE) {
						iteration = Integer.parseInt(msg.getUserDefinedParameter("negotiationIteration"));
						iteration++;
						reply = msg.createReply();
						reply.setPerformative(ACLMessage.CFP);
						reply.addUserDefinedParameter("negotiationIteration", iteration.toString());
						//reply.addUserDefinedParameter("debugging", "negotiated");
						reply.setContent(new DecimalFormat("0.00").format(askingPrice));
						replies.addElement(reply);
//						System.out.println("Auction: " + myAgent.getLocalName() + " - " + msg.getSender().getLocalName() + " Continuing negotiation with $" + new DecimalFormat("0.00").format(askingPrice) + "/kWh. (Iteration: "+ iteration +")");
					}
				}
				newIteration(replies);
			} else {
				ACLMessage msg = acceptList.get(0); 
				iteration = Integer.parseInt(msg.getUserDefinedParameter("negotiationIteration"));
				iteration++;
				reply = msg.createReply();
				reply.setPerformative(ACLMessage.ACCEPT_PROPOSAL);
				reply.addUserDefinedParameter("negotiationIteration", iteration.toString());
				reply.addUserDefinedParameter("debugging", "accepted");
//				System.out.println("Auction: " + myAgent.getLocalName() + " - " + msg.getSender().getLocalName() + " Accepting price of $" +  msg.getContent() + "/kWh. (Iteration: "+ iteration +")");
				replies.add(reply);
				acceptances.addAll(replies);
			}
		}	
		
//		while (e.hasMoreElements()) {
//			ACLMessage msg = e.nextElement();
//			iteration = Integer.parseInt(msg.getUserDefinedParameter("negotiationIteration"));
//			if (msg.getPerformative() == ACLMessage.PROPOSE) {
//				reply = msg.createReply();
//				reply.setPerformative(ACLMessage.REJECT_PROPOSAL);
//				replies.addElement(reply);
//				double proposal = 0.0;
//				if(msg.getUserDefinedParameter("proposedPrice") != null) {
//					proposal = Double.parseDouble(msg.getUserDefinedParameter("proposedPrice"));
//				}
//				if(iteration == 0){
//					askingPrice = proposal * 0.80;
//					reply.addUserDefinedParameter("buyerAskingPrice", String.format("%.2f", askingPrice));	
//
//					/*if(askingPrice <= proposal) {
//					bestProposal = proposal;
//					bestProposer = msg.getSender();
//					accept = reply;
//					} 
//
//						else if (proposal > askingPrice) {
//
//					} */ //from old code
//					iteration++;
//					reply.addUserDefinedParameter("negotiationIteration", iteration.toString());
//
//				}else{
//					if(msg.getUserDefinedParameter("buyerAskingPrice") != null) {
//						askingPrice = Double.parseDouble(msg.getUserDefinedParameter("buyerAskingPrice"));
//					}
//					if(askingPrice <= proposal){
//						bestProposal = proposal;
//						bestProposer = msg.getSender();
//						accept = reply;
//
//					}else{
//						iteration++;
//						reply.addUserDefinedParameter("negotiationIteration", iteration.toString());
//
//					}
//				}
//
//				//Decide if price is within reason
//				//If not, reject proposal
//				//Otherwise create new list of vendors for next iteration
//
//				//Decide if price is acceptable
//
//
//
//				//send reply
//			}
//		}
//		// Accept the proposal of the best proposer
//		if (accept != null) {
//			System.out.println("Auction: " + myAgent.getAID().getLocalName()+": Accepting $"+bestProposal+"/kWh from "+bestProposer.getLocalName() + ".");
//			accept.setPerformative(ACLMessage.ACCEPT_PROPOSAL);
//		}
	}

	/*
		// Accept the proposal of the best proposer
		if (accept != null) {
			System.out.println("Auction: " + myAgent.getAID().getLocalName()+": Accepting $"+bestProposal+"/kWh from "+bestProposer.getLocalName() + ".");
			accept.setPerformative(ACLMessage.ACCEPT_PROPOSAL);
		}*/						

	protected void handleInform(ACLMessage inform) {
		((BuyerAgent)myAgent).receiveEnergy(Double.parseDouble(inform.getUserDefinedParameter("energy-provided")));
		((BuyerAgent)myAgent).isPurchasing = false;
		//System.out.print(BuyerAgent.energyFormat.format(((BuyerAgent)myAgent).getEnergyUsed()));
		//System.out.println("Auction: " + myAgent.getAID().getLocalName()+" received " + inform.getUserDefinedParameter("energy-provided") + "kWh from "+inform.getSender().getLocalName()+".");
	}
}
